<?php
require_once 'common.php';
require_once 'OaCompanyModel.php';
require_once 'OaAppModel.php';

/**
 * 权限模型
 * @author wangjiajun
 *
 */
class OaAuthorityModel extends OpModel
{
    // 角色
    const ROLE_COMPANY_ADMIN = 'company.admin';             // 公司管理员
    const ROLE_COMPANY_PM = 'company.pm';                   // 产品经理
    const ROLE_COMPANY_EMPLOYEE = 'company.employee';       // 普通员工
    const ROLE_APP_ADMIN = 'app.admin';                     // 产品管理员
    const ROLE_APP_DEVELOPER = 'app.developer';             // 产品开发
    const ROLE_APP_OPERATOR = 'app.operator';               // 产品运维
    
    // 公司相关操作
    const OP_VIEW_COMPANY = 'company.view';                                // 访问公司
    const OP_CREATE_APP = 'company.create_app';                            // 创建应用
    /*const OP_VIEW_OPERATION_DATA = 'company.view_operation_data';          // 查看运营数据
    const OP_USE_OPERATION_TOOL = 'company.use_operation_tool';            // 使用运营工具
    const OP_CHECK_ACCOUNT = 'company.check_account';                      // 对账
    const OP_QUERY_BILLING_ORDER = 'company.query_billing_order';          // 计费订单查询  */    
    const OP_COMPANY_ROLE_ASSIGN = 'company.role_assign';                  // 公司角色分配
    const OP_COMPANY_ROLE_REVOKE = 'company.role_revoke';                  // 公司角色回收
    const OP_COMPANY_ROLE_TRASNFER = 'company.role_transer';               // 公司角色转让
    //const OP_MANAGE_TEST_ACCOUNT = 'company.manage_test_account';        // 测试帐号管理
    //const OP_APP_POINT_ASSIGN = 'company.point_assign';                    // 分配点券
    const OP_APP_ADMIN_GRANT = 'company.app_admin_grant';                  // 应用管理员指定
    const OP_COMPANY_ALL = 'company.*';                                    // 所有公司操作
    
    // 应用相关操作
    
    const OP_VIEW_APP = 'app.view';                                        // 访问应用    
    const OP_FILL_IN_BASIC_INFO = 'app.fill_in_basic_info';                // 填写基本信息
    const OP_SELECT_SERVICE = 'app.select_service';                        // 选择服务
    const OP_APPLY_FOR_TESTING = 'app.apply_for_testing';                  // 申请测试
    const OP_PRODUCTION_CONFIG = 'app.production_config';                  // 正式环境配置
    const OP_APPLY_FOR_RELEASE = 'app.apply_for_release';                  // 申请上线
    const OP_APP_ROLE_ASSIGN = 'app.role_assign';                          // 应用角色分配
    const OP_APP_ROLE_REVOKE = 'app.role_revoke';                          // 应用角色收回
    const OP_VIEW_OPERATION_DATA = 'app.view_operation_data';              // 查看运营数据
    const OP_USE_OPERATION_TOOL = 'app.use_operation_tool';                // 使用运营工具
    const OP_CHECK_ACCOUNT = 'app.check_account';                          // 对账
    const OP_QUERY_BILLING_ORDER = 'app.query_billing_order';              // 计费订单查询
    const OP_MANAGE_TEST_ACCOUNT = 'app.manage_test_account';        // 测试帐号管理（查看，添加，删除）
    
    const OP_APP_ALL = 'app.*';                                            // 所有应用操作
    
    const OP_ALL = '*';                                                    // 所有操作
    const ROLE_TABLE = "role";
    
    public static $role = array(
        self::ROLE_COMPANY_ADMIN => array(
            'name' => '公司管理员'
        ),
        self::ROLE_COMPANY_PM => array(
            'name' => '产品经理'
        ),
        self::ROLE_COMPANY_EMPLOYEE => array(
            'name' => '普通员工'
        ),
        self::ROLE_APP_ADMIN => array(
            'name' => '产品管理员'
        ),
        self::ROLE_APP_DEVELOPER => array(
            'name' => '产品开发'
        ),
        self::ROLE_APP_OPERATOR => array(
            'name' => '产品运维'
        )
    );
    
    private $_operationTable;
    private $_authorityTable;
    private $_roleTableDb;
    private $_appModel;
    private $_companyModel;
    
    public static function getConstantValueByName($name, $default = 0)
    {
        return self::_getConstByName($name, '', $default, 'OaAuthorityModel');
    }
    
    public function __construct($logger = null)
    {
        if (is_null($logger)) {
            $logger = getOaModelLogger();
        }
        parent::__construct($logger);
        $dbConfig = Oa_Util_Config::getSingleDbConfig(OA_WEB_DB_CLUSTER_ID);
        $db = OpDbModel::getInstance($dbConfig, $logger);
        $this->_operationTable = new OpTableModel($db, 'operation', $logger);
        $this->_authorityTable = new OpTableModel($db, 'authority', $logger);
        $this->_roleTableDb = new OpTableModel($db, self::ROLE_TABLE, $logger);
        $this->_appModel = new OaAppModel(OaAppModel::APP_CONFIG_ENV_PRODUCTION, $logger);
        $this->_companyModel = new OaCompanyModel($logger);
    }
    
    /**
     * 新增操作
     * 操作命名遵照company.create_app的分组方式，这样在授权的时候可以一次授予某组下的所有操作
     * @param string $name
     * @param string $desc
     * @return boolean 如果已添加过，设置错误号1
     */
    public function addOperation($name, $desc = '')
    {
        if ($this->getOperation($name) !== null) {
            $this->_setError(1, "already exists");
            return false;
        }
        return $this->_operationTable->insert(array(
            'name' => $name,
            'description' => $desc,
            'create_time' => date('Y-m-d H:i:s')
        ), null, false);
    }
    
    /**
     * 查询操作
     * @param string $name
     * @return array|null|boolean
     */
    public function getOperation($name)
    {
        return $this->_operationTable->getRow(array(
            'name' => $name
        ));
    }
    /**
     * 添加新的管理职位
     * @param string $name
     * @param string $desc
     * 
     * @return boolean
     */
    public function addRole($name, $desc)
    {
        if ($this->_roleTableDb->getRow(array('name'=>$name))) {
            $this->_setError(1, "already exists");
            return false;
        }
        return $this->_roleTableDb->insert(array(
            'name'=>$name,
            'description'=>$desc,
            'create_time'=>date("Y-m-d H:i:s")
        ));
    }
    /**
     * 获取角色列表
     * @param int $offset
     * @param int $count
     * 
     * @return array
     */
    public function getRoleList ($offset = 0, $count = null)
    {
        return $this->_roleTableDb->get(null, $offset, $count, 'create_time ASC');
    }
    /**
     * 查询操作列表
     * @param int $offset
     * @param int $count
     * @return array|boolean
     */
    public function getOperationList ($offset = 0, $count = null)
    {
        return $this->_operationTable->get(null, $offset, $count, 'create_time ASC');
    }
    /**
     * 删除操作
     * @param string $name
     * @return boolean
     */
    public function deleteOperation ($name)
    {
        if ($this->deleteAuthorityByOperation($name) === false) {
            $this->_logger->log("delete authority by operation failed");
            return false;
        }
        return $this->_operationTable->delete(array(
            'name' => $name
        ));
    }
    /**
     * 授权某个角色某种操作
     * @param string $role
     * @param string $operation 可以授权某组下的所有操作，比如company.*，如果要授权所有操作，传递*
     * @return boolean 如果已经授权过，设置错误号1
     */
    public function authorize ($role, $operation)
    {
        if ($this->getAuthority($role, $operation) !== null) {
            $this->_setError(1, "already exists");
            return false;
        }
        return $this->_authorityTable->insert(array(
            'role' => $role,
            'operation' => $operation,
            'create_time' => date('Y-m-d H:i:s')
        ), null, false);
    }
    /**
     * 根据角色和操作查询授权记录
     * @param string $role
     * @param string $operation
     * @return array|null|boolean
     */
    public function getAuthority($role, $operation)
    {
        return $this->_authorityTable->getRow(array(
            'role' => $role,
            'operation' => $operation
        ));
    }
    /**
     * 
     * @param string $role
     * @param array $ops
     */
    public function getAuthorityByOPMulti($role, $ops)
    {
       if(!is_array($ops) || count($ops)==1){
           return $this->getAuthority($role, $ops);
       }
       return $this->_authorityTable->get(array(
            'role' => $role,
            'operation' => $ops
        ));
    }
    /**
     * 收回某个角色的 某种操作
     * @param string $role
     * @param string $operation
     * @return boolean
     */
    public function revoke($role, $operation)
    {
        return $this->_authorityTable->delete(array(
            'role' => $role,
            'operation' => $operation
        ));
    }
    /**
     * 获取管理员允许的公司级操作动作
     * @param int $developerId
     * @param int $companyId
     * 
     * return array(company.view=>true, ,,,)
     */
    public function getCompanyAuthorityOPS ($developerId, $companyId)
    {
        $companyOP = array(
            'company.view' => false, 
            'company.create_app' => false, 
            'company.role_assign' => false, 
            'company.role_revoke' => false, 
            'company.role_transer' => false, 
            'company.app_admin_grant' => false
        );
        if (! $companyId || !$developerId) {
            return $companyOP;
        }
        $row = $this->_companyModel->getDeveloper($companyId, $developerId);
        if ($row === false) {
            //$this->_logger->log("get developer failed");
            return $companyOP;
        }
        if (is_null($row)) {
            //$this->_logger->log("developer not belong to company");
            return $companyOP;
        }
        if ($this->checkCompanyAuthority($developerId, $companyId, self::OP_COMPANY_ALL)) {
            foreach ($companyOP as $k => $val) {
                $companyOP[$k] = true;
            }
        } else {
            $opList = $this->getAuthorityByOPMulti($row['role'], array_keys($companyOP));
            if ($opList) {
                foreach ($opList as $row) {
                    $companyOP[$row['operation']] = true;
                }
            }
        }
        return $companyOP;
    }
    /**
     * 获取管理员允许的产品级操作动作
     * @param int $developerId
     * @param int $appId
     * 
     * return array(app.view=>true, ,,,)
     */
    public function getAppAuthorityOPS ($developerId, $appId)
    {
        $appOP = array(
            'app.view' => false, 
            'app.fill_in_basic_info' => false, 
            'app.select_service' => false, 
            'app.apply_for_testing' => false, 
            'app.production_config' => false, 
            'app.apply_for_release' => false, 
            'app.role_assign' => false, 
            'app.role_revoke' => false, 
            'app.view_operation_data' => false, 
            'app.use_operation_tool' => false, 
            'app.check_account' => false, 
            'app.query_billing_order' => false, 
            'app.manage_test_account' => false
        );
        if (! $appId || !$developerId) {
            return $appOP;
        }
        $appRow = $this->_appModel->getApp($appId, array(
            'company_id'
        ));
        if (! $appRow) {
            //$this->_logger->log("app is not exists");
            return $appOP;
        }
        if ($this->checkCompanyAuthority($developerId, $appRow['company_id'], self::OP_COMPANY_ALL) || $this->checkAppAuthority(
        $developerId, $appId, self::OP_APP_ALL)) {
            foreach ($appOP as $k => $val) {
                $appOP[$k] = true;
            }
            return $appOP;
        }
        $row = $this->_appModel->getDeveloper($appId, $developerId);
        if ($row === false) {
            //$this->_logger->log("get developer failed");
            return $appOP;
        }
        if (is_null($row)) {
            //$this->_logger->log("developer not belong to company");
            return $appOP;
        }
        $opList = $this->getAuthorityByOPMulti($row['role'], array_keys($appOP));
        if ($opList) {
            foreach ($opList as $row) {
                $appOP[$row['operation']] = true;
            }
        }
        return $appOP;
    }
    /**
     * 检查公司权限
     * @param int $developerId
     * @param int $companyId
     * @param string $operation
     * @return boolean 如果开发者具有该操作权限，返回true，否则返回false
     */
    public function checkCompanyAuthority($developerId, $companyId, $operation)
    {
        //$companyModel = new OaCompanyModel($this->_logger);
        $row = $this->_companyModel->getDeveloper($companyId, $developerId);
        if ($row === false) {
            //$this->_logger->log("get developer failed");
            return false;
        }
        if (is_null($row)) {
            //$this->_logger->log("developer not belong to company");
            return false;
        }
        return $this->checkAuthority($row['role'], $operation);
    }
    
    /**
     * 检查应用权限
     * @param int $developerId
     * @param int $appId
     * @param string $operation
     * @return boolean 如果开发者具有该操作权限，返回true，否则返回false
     */
    public function checkAppAuthority($developerId, $appId, $operation)
    {
        //$appModel = new OaAppModel(OaAppModel::APP_CONFIG_ENV_PRODUCTION, $this->_logger);
        $appRow = $this->_appModel->getApp($appId, array('company_id'));
        if(!$appRow){
            //$this->_logger->log("app is not exists");
            return false;
        }
        if($this->checkCompanyAuthority($developerId, $appRow['company_id'], self::OP_COMPANY_ALL)){
            return true;
        }
        $row = $this->_appModel->getDeveloper($appId, $developerId);
        if ($row === false) {
            //$this->_logger->log("get developer failed");
            return false;
        }
        if (is_null($row)) {
            //$this->_logger->log("developer not belong to app", PEAR_LOG_INFO);
            return false;
        }
        return $this->checkAuthority($row['role'], $operation);
    }
    
    /**
     * 检查某个角色是否具备某种操作权限
     * @param string $role
     * @param string $operation
     * @return boolean
     */
    public function checkAuthority($role, $operation)
    {
        $parts = explode('.', $operation);
        $len = count($parts);
        $authoritys = array('*');
        for ($i = 0; $i < $len; $i++) {
            $tmp = array();
            for ($j = 0; $j <= $i; $j++) {
                $tmp[] = $parts[$j];
            }
            if ($j < $len) {
                $tmp[] = '*';
            }
            $authoritys[] = implode('.', $tmp);
        }
        return is_array($this->getAuthority($role, $authoritys));
        /*foreach ($authoritys as $operation) {
            if (is_array($this->getAuthority($role, $operation))) {
                return true;
            }
        }
        return false;*/
    }
    
    /**
     * 根据角色删除授权记录
     * @param string $role
     * @return boolean
     */
    public function deleteAuthorityByRole($role)
    {
        return $this->_authorityTable->delete(array(
            'role' => $role
        ));
    }
    
    /**
     * 根据操作删除授权记录
     * @param string $role
     * @return boolean
     */
    public function deleteAuthorityByOperation($operation)
    {
        return $this->_authorityTable->delete(array(
            'operation' => $operation
        ));
    }
}
